package com.logic.landseaserver.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import com.logic.common.exception.BusinessException;
import com.logic.common.security.SecurityUtils;
import com.logic.common.util.QueryCriteria;
import com.logic.common.util.QueryUtil;
import com.logic.landseaserver.common.LandseaErrorMessageEnum;
import com.logic.landseaserver.common.enums.remould.AuditStatusEnum;
import com.logic.landseaserver.common.enums.remould.ConstructStatusEnum;
import com.logic.landseaserver.common.enums.remould.DisplayStatusEnum;
import com.logic.landseaserver.common.exception.LandseaBusinessException;
import com.logic.landseaserver.domain.AuditLog;
import com.logic.landseaserver.domain.Check;
import com.logic.landseaserver.domain.Procedure;
import com.logic.landseaserver.domain.RemouldProject;
import com.logic.landseaserver.persistence.read.ProcedureReadMapper;
import com.logic.landseaserver.persistence.read.RemouldProjectListReadMapper;
import com.logic.landseaserver.persistence.read.RemouldProjectReadMapper;
import com.logic.landseaserver.persistence.write.AuditLogWriteMapper;
import com.logic.landseaserver.persistence.write.RemouldProjectWriteMapper;
import com.logic.landseaserver.service.ICheckService;
import com.logic.landseaserver.service.IProcedureService;
import com.logic.landseaserver.service.IRemouldProjectService;
import com.logic.landseaserver.ws.dto.PropertyDTO;
import com.logic.landseaserver.ws.dto.RemouldProjectDTO;
import com.logic.landseaserver.ws.dto.RemouldProjectListDTO;
import com.logic.system.domain.PersonalInfo;
import com.logic.system.domain.Role;
import com.logic.system.domain.User;
import com.logic.system.persistence.read.PersonalInfoReadMapper;
import com.logic.system.persistence.read.RoleReadMapper;
import com.logic.system.persistence.read.UserReadMapper;
import com.logic.system.service.impl.AddressService;
import com.logic.system.ws.dto.AddressDto;

@Service
public class RemouldProjectServiceImpl implements IRemouldProjectService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());
    
	@Autowired
	private RemouldProjectReadMapper remouldProjectReadMapper;

	@Autowired
	private RemouldProjectWriteMapper remouldProjectWriteMapper;

	@Autowired
	private IProcedureService procedureServiceImpl;

	@Autowired
	private ICheckService checkServiceImpl;

	@Autowired
	private AddressService addressService;

	@Autowired
	private RemouldProjectListReadMapper remouldProjectListReadMapper;

	@Autowired
	private UserReadMapper userReadMapper;

	@Autowired
	private  PersonalInfoReadMapper personalInfoReadMapper;

	@Autowired
	private AuditLogWriteMapper auditLogWriteMapper;
	@Autowired
	private RoleReadMapper roleReadMapper;

	@Autowired
	private ProcedureReadMapper procedureReadMapper;

	@Override
	public void delete(String arg0) throws BusinessException {
		String[] idArr = arg0.split(",");
		for (String id : idArr) {
			Integer remouldProjectId = Integer.valueOf(id);
			RemouldProject remouldProject = (RemouldProject) this.get(remouldProjectId);
			Boolean pass = this.validateForDelete(remouldProject);
			if (pass) {
				remouldProject.updateCommonInfo(SecurityUtils.getCurrentLogin().getUserId());
				remouldProjectWriteMapper.deleteByPrimaryKey(remouldProject);
			}
		}

	}

	@Override
	public Object get(Integer arg0) throws BusinessException {
		return remouldProjectReadMapper.selectByPrimaryKey(arg0);
	}

	@Override
	public int insert(Object arg0) throws BusinessException {
		Integer id = -1;
		Boolean pass = this.validateForInsert(arg0);
		if (pass) {
			RemouldProject remouldProject = (RemouldProject) arg0;
			Boolean template = remouldProject.getTemplate();
			if (template != null && template.equals(false)) {
				remouldProject.setSerialNum(System.currentTimeMillis() + "");
			}
			remouldProject.updateCommonInfo(SecurityUtils.getCurrentLogin().getUserId());
			remouldProjectWriteMapper.insertSelective(remouldProject);
			id = remouldProject.getId();
		}
		return id;
	}

	@Override
	public List<?> query(QueryUtil arg0) {
		return remouldProjectReadMapper.getRemouldProjectList(arg0);
	}

	@Override
	public void update(Object arg0) throws BusinessException {
		Boolean pass = this.validateForUpdate(arg0);
		if (pass) {
			RemouldProject remouldProject = (RemouldProject) arg0;
			remouldProject.updateCommonInfo(SecurityUtils.getCurrentLogin().getUserId());
			remouldProject.setCreatedBy(null);
			remouldProject.setCreatedDtm(null);
			if (AuditStatusEnum.PASS.getCode().equals(remouldProject.getAuditStatus())) {
				remouldProject.setWorkStatus(ConstructStatusEnum.PENDING_OPEN.getCode());
			}
			remouldProjectWriteMapper.updateByPrimaryKeySelective(remouldProject);
			Integer projectId = remouldProject.getId();
			updateDisplayStatus(projectId);
		}

	}

	@Async
	private void updateDisplayStatus(Integer projectId) throws BusinessException {
		RemouldProject remouldProject = (RemouldProject) this.get(projectId);
		if (remouldProject != null) {
			String workStatus = remouldProject.getWorkStatus();
			String auditStatus = remouldProject.getAuditStatus();
			String displayStatus = null;
			RemouldProject newProject = new RemouldProject();
			if (AuditStatusEnum.PASS.getCode().equals(auditStatus)) {
				if (ConstructStatusEnum.PENDING_OPEN.getCode().equals(workStatus)) {
					displayStatus = DisplayStatusEnum.PENDING_OPEN.getCode();
				} else if (ConstructStatusEnum.GOING.getCode().equals(workStatus)) {
					displayStatus = DisplayStatusEnum.GOING.getCode();
				} else if (ConstructStatusEnum.DELAY.getCode().equals(workStatus)) {
					displayStatus = DisplayStatusEnum.DELAY.getCode();
				}  else if (ConstructStatusEnum.COMPLETE.getCode().equals(workStatus)) {
					displayStatus = DisplayStatusEnum.COMPLETE.getCode();
				}
			} else if (workStatus == null) {
				if (AuditStatusEnum.DRAFT.getCode().equals(auditStatus)) {
					displayStatus = DisplayStatusEnum.DRAFT.getCode();
				} else if (AuditStatusEnum.PENDING_CONFIGURE.getCode().equals(auditStatus)) {
					displayStatus = DisplayStatusEnum.PENDING_CONFIGURE.getCode();
				} else if (AuditStatusEnum.PENDING_AUDIT.getCode().equals(auditStatus)) {
					displayStatus = DisplayStatusEnum.PENDING_AUDIT.getCode();
				} else if (AuditStatusEnum.APPLY_CHANGE.getCode().equals(auditStatus)) {
					displayStatus = DisplayStatusEnum.APPLY_CHANGE.getCode();
				} else if (AuditStatusEnum.CANCELED.getCode().equals(auditStatus)) {
					displayStatus = DisplayStatusEnum.CANCELED.getCode();
				}
			} else if (workStatus != null) {
				if (AuditStatusEnum.DRAFT.getCode().equals(auditStatus)) {
					displayStatus = DisplayStatusEnum.CHANGE_PENDING_PUBLISH.getCode();
				} else if (AuditStatusEnum.PENDING_CONFIGURE.getCode().equals(auditStatus)) {
					displayStatus = DisplayStatusEnum.CHANGE_PENDING_CONFIGURE.getCode();
				} else if (AuditStatusEnum.PENDING_AUDIT.getCode().equals(auditStatus)) {
					displayStatus = DisplayStatusEnum.CHANGE_PENDING_AUDIT.getCode();
				} else if (AuditStatusEnum.APPLY_CHANGE.getCode().equals(auditStatus)) {
					displayStatus = DisplayStatusEnum.APPLY_CHANGE.getCode();
				} else if (AuditStatusEnum.CANCELED.getCode().equals(auditStatus)) {
					displayStatus = DisplayStatusEnum.CANCELED.getCode();
				}
			}
			newProject.setId(remouldProject.getId());
			newProject.setDisplayStatus(displayStatus);
			remouldProjectWriteMapper.updateByPrimaryKeySelective(newProject);
		}

	}

	@Override
	public Boolean validate(Object arg0) throws BusinessException {
		Boolean pass = true;
		if (arg0 == null) {
			throw new LandseaBusinessException(LandseaErrorMessageEnum.RemouldProject_Insert_Or_Update_Empty_Object);
		}
		if (!(arg0 instanceof RemouldProject)) {
			throw new LandseaBusinessException(LandseaErrorMessageEnum.RemouldProject_Insert_Or_Update_Type);
		}
		RemouldProject remouldProject = (RemouldProject) arg0;
		if (remouldProject.getTemplate() != null && remouldProject.getTemplate()) {
			RemouldProject nameRemouldProject = remouldProjectReadMapper.selectByName(remouldProject.getName());
			if (nameRemouldProject != null  && !nameRemouldProject.getId().equals(remouldProject.getId())) {
				throw new LandseaBusinessException(LandseaErrorMessageEnum.RemouldProject_Insert_Or_Update_Name_Repeat);
			}
		}
		return pass;
	}

	@Override
	public Boolean validateForDelete(Object arg0) throws BusinessException {
		return true;
	}

	@Override
	public Boolean validateForInsert(Object arg0) throws BusinessException {
		Boolean pass = false;
		pass = this.validate(arg0);
		RemouldProject remouldProject = (RemouldProject)arg0;
		if (remouldProject.getId() != null) {
			throw new LandseaBusinessException(LandseaErrorMessageEnum.RemouldProject_CreateRemouldProject_Empty_ID);
		}
		if (StringUtils.isBlank(remouldProject.getName())) {
			throw new LandseaBusinessException(LandseaErrorMessageEnum.RemouldProject_CreateProcedure_Empty_RemouldProject_Name);
		}
		if (StringUtils.isBlank(remouldProject.getDescription())) {
			throw new LandseaBusinessException(LandseaErrorMessageEnum.RemouldProject_CreateRemouldProject_Empty_RemouldProject_Description);
		}
		return pass;
	}

	@Override
	public Boolean validateForUpdate(Object arg0) throws BusinessException {
		Boolean pass = false;
		pass = this.validate(arg0);
		RemouldProject remouldProject = (RemouldProject)arg0;
		if (remouldProject.getId() == null) {
			throw new LandseaBusinessException(LandseaErrorMessageEnum.RemouldProject_UpdateRemouldProject_Empty_RemouldProject_ID);
		}
		return pass;
	}

	@Override
	public RemouldProjectDTO getDTO(Integer id) throws BusinessException {
		RemouldProjectDTO remouldProjectDTO = remouldProjectReadMapper.selectDTOByPrimaryKey(id);
		PropertyDTO propertyDTO = remouldProjectDTO.getPropertyDTO();
		if (remouldProjectDTO != null && propertyDTO != null
				&& propertyDTO.getAddressId() != null) {
			List<Procedure> procedures = procedureReadMapper.notPassedProcedure(remouldProjectDTO.getId());
			if (procedures == null) {
				remouldProjectDTO.setAllProcedurePass(true);
			}
			buildAddressDTO(propertyDTO);
		}
		return remouldProjectDTO;
	}

	private void buildAddressDTO(PropertyDTO propertyDTO) {
		Integer addressId = propertyDTO.getAddressId();
		if (addressId != null) {
			StringBuffer fullName = new StringBuffer();
			AddressDto addressDto = addressService.queryDetailById(addressId);
			if(addressDto != null) {
				String province = addressDto.getProvince();
				String city = addressDto.getCity();
				String county = addressDto.getCounty();
				String addressLine = addressDto.getAddressLine();
				fullName.append(province == null ? "" : province).append(city == null ? "" : city).append(county == null ? "" : county)
				.append(addressLine == null ? "" : addressLine);
				addressDto.setFullAddress(fullName.toString());
				propertyDTO.setAddressDto(addressDto);
			}
		}
	}

	@Override
	public List<RemouldProjectDTO> queryDTO(QueryUtil queryUtil) {
		List<RemouldProjectDTO> remouldProjectDTOList = remouldProjectReadMapper.getRemouldProjectDTOList(queryUtil);
		this.setNum(remouldProjectDTOList);
		return remouldProjectDTOList;
	}

	private void setNum(List<RemouldProjectDTO> remouldProjectDTOList) {
		for (RemouldProjectDTO remouldProjectDTO : remouldProjectDTOList) {
			remouldProjectDTO.setProcedureNum((procedureServiceImpl.countByProjectId(remouldProjectDTO.getId())));
		}
	}

	@Override
	public Procedure addProcedure(Integer projectId, Procedure newProcedure) throws BusinessException {
		//whether put in storage
		if (newProcedure.getTemplate()) {
			procedureServiceImpl.add2Template(newProcedure);
		}
		newProcedure.setTemplate(false);
		newProcedure.setId(null);
		procedureServiceImpl.insert(newProcedure);
		Integer newProcedureId = newProcedure.getId();
		remouldProjectWriteMapper.insertRemouldProjectProcedure(projectId, newProcedureId);
		return newProcedure;
	}

	@Override
	public Procedure addProcedure(Integer projectId, Integer procedureId) throws BusinessException {
		Procedure procedure = procedureServiceImpl.copyFromTemplate(procedureId);

		Integer newProcedureId = procedure.getId();
		remouldProjectWriteMapper.insertRemouldProjectProcedure(projectId, newProcedureId);
		return procedure;
	}


	@Override
	public void removeProcedure(Integer projectId, Integer procedureId) {
		try {
			procedureServiceImpl.delete(String.valueOf(procedureId));
			remouldProjectWriteMapper.deleteRemouldProjectProcedure(projectId, procedureId);
		} catch (BusinessException e) {
		    logger.error("removeProcedure error.", e);
		}


	}

	@Override
	public void addProcedure(Integer projectId, String procedureIds) throws BusinessException {
		String[] idArr = procedureIds.split(",");
		for (String id : idArr) {
			Integer procedureId = Integer.valueOf(id);
			this.addProcedure(projectId, procedureId);
		}

	}

	@Override
	public void removeProcedure(Integer projectId, String procedureIds) throws BusinessException {
		String[] idArr = procedureIds.split(",");
		for (String id : idArr) {
			Integer procedureId = Integer.valueOf(id);
			this.removeProcedure(projectId, procedureId);
		}

	}

	@Override
	public void batchAddProcedure(Integer projectId, List<Procedure> newProcedure) throws BusinessException {
		for (Procedure procedure : newProcedure) {
			if (StringUtils.isBlank(procedure.getSerialNum())) {
				procedure.setSerialNum(System.currentTimeMillis() + "");
			}
			Integer procedureId = procedureServiceImpl.insert(procedure);
			this.buildProcedureCheck(procedure);
			procedureServiceImpl.update(procedure);
			remouldProjectWriteMapper.insertRemouldProjectProcedure(projectId, procedureId);
		}

	}

	@Override
	public RemouldProject copyFromTemplate(Integer projectId) throws BusinessException {
		RemouldProject template = (RemouldProject) this.get(projectId);
		RemouldProject newRemouldProject = this.buildRemouldProject(template);
		this.insert(newRemouldProject);
		this.buildProjectProcedure(template.getId(), newRemouldProject.getId());
		return newRemouldProject;
	}

	private RemouldProject buildRemouldProject(RemouldProject template) {
		RemouldProject remouldProject = new RemouldProject();
		remouldProject.setActualEndDtm(template.getActualEndDtm());
		remouldProject.setActualStartDtm(template.getActualStartDtm());
		remouldProject.setArea(template.getArea());
		remouldProject.setAuditStatus(template.getAuditStatus());
		remouldProject.setChangeCityManagerAudit(template.getChangeCityManagerAudit());
		remouldProject.setChangeDirectorAudit(template.getChangeDirectorAudit());
		remouldProject.setChangeDuration(template.getChangeDuration());
		remouldProject.setChangeId(template.getChangeId());
		remouldProject.setChangePerson(template.getChangePerson());
		remouldProject.setCityManager(template.getCityManager());
		remouldProject.setConstructUnit(template.getConstructUnit());
		remouldProject.setDescription(template.getDescription());
		remouldProject.setDisplayStatus(template.getDisplayStatus());
		remouldProject.setDuration(template.getDuration());
		remouldProject.setEstimateEndDtm(template.getEstimateEndDtm());
		remouldProject.setEstimateStartDtm(template.getEstimateStartDtm());
		remouldProject.setName(template.getName());
		remouldProject.setProjectManager(template.getProjectManager());
		remouldProject.setPropertyId(template.getPropertyId());
		remouldProject.setRepairProjectId(template.getRepairProjectId());
		remouldProject.setSerialNum(template.getSerialNum());
		remouldProject.setType(template.getType());
		remouldProject.setWorkStatus(template.getWorkStatus());
		remouldProject.setTemplate(false);
		return remouldProject;
	}

	private void buildProjectProcedure(Integer templateId, Integer projectId) throws BusinessException {
		List<Procedure> procedures = procedureServiceImpl.getByProjectId(templateId);
		if (procedures != null && procedures.size() > 0) {
			for (Procedure procedure : procedures) {
				Procedure newProcedure = procedureServiceImpl.copyFromTemplate(procedure.getId());
				remouldProjectWriteMapper.insertRemouldProjectProcedure(projectId, newProcedure.getId());
			}
		}
	}

	private void buildProcedureCheck(Procedure procedure) throws BusinessException {
		Check startCheck = checkServiceImpl.copyFromTemplate(procedure.getStartCheckId());
		Check endCheck = checkServiceImpl.copyFromTemplate(procedure.getEndCheckId());
		procedure.setStartCheckId(startCheck.getId());
		procedure.setEndCheckId(endCheck.getId());
	}

	@Override
	public void chooseTemplate(Integer projectId, Integer templateId) throws BusinessException {
		this.buildProjectProcedure(templateId, projectId);

	}

	//项目列表
	@Override
	public List<RemouldProjectListDTO> queryList(QueryUtil queryUtil) {
		Integer userId = SecurityUtils.getCurrentLogin().getUserId();
		List<Role>  roles = roleReadMapper.getRolesByUserID(userId);
		List<String> roleNames = roles.stream().map(Role::getCode).collect(Collectors.toList());
		if (roleNames != null && roleNames.contains("RC001")) {

		} else {
			for (Role role : roles) {
				String code = role.getCode();
				if ("RC005".equals(code)) {
					QueryCriteria  queryCriteria = new QueryCriteria();
					queryCriteria.setConnection("and");
					queryCriteria.setKey("project_manager");
					queryCriteria.setCondition("=");
					queryCriteria.setValue(userId + "");
					queryCriteria.setIsValueADigital(true);

					QueryCriteria  queryCriteria1 = new QueryCriteria();
					queryCriteria1.setConnection("and");
					queryCriteria1.setKey("audit_status");
					queryCriteria1.setCondition("!=");
					String audit_status = AuditStatusEnum.DRAFT.getCode();
					queryCriteria1.setValue(audit_status);
					queryCriteria1.setIsValueADigital(false);

					if (queryUtil.getQueryCriterias() != null) {
						List<QueryCriteria> queryCriterias = queryUtil.getQueryCriterias();
						queryCriterias.add(queryCriteria);

						queryCriterias.add(queryCriteria1);
						queryUtil.setQueryCriterias(queryCriterias);


						queryUtil.setQueryCriterias(queryCriterias);

					}
					else {
						List<QueryCriteria> queryCriterias = new ArrayList<QueryCriteria>();
						queryCriterias.add(queryCriteria);
						queryCriterias.add(queryCriteria1);
						queryUtil.setQueryCriterias(queryCriterias);
					}
				}
				else if ("RC002".equals(code)) {
					QueryCriteria  queryCriteria = new QueryCriteria();
					queryCriteria.setConnection("and");
					queryCriteria.setKey("city_manager");
					queryCriteria.setCondition("=");
					queryCriteria.setValue(userId + "");
					queryCriteria.setIsValueADigital(true);

					QueryCriteria  queryCriteria1 = new QueryCriteria();
					queryCriteria1.setConnection("and");
					queryCriteria1.setKey("audit_status");
					queryCriteria1.setCondition("!=");
					String audit_status = AuditStatusEnum.DRAFT.getCode();
					queryCriteria1.setValue(audit_status);
					queryCriteria1.setIsValueADigital(false);


					if (queryUtil.getQueryCriterias() != null) {
						List<QueryCriteria> queryCriterias = queryUtil.getQueryCriterias();
						queryCriterias.add(queryCriteria);

						queryCriterias.add(queryCriteria1);
						queryUtil.setQueryCriterias(queryCriterias);

						queryUtil.setQueryCriterias(queryCriterias);
					}
					else {
						List<QueryCriteria> queryCriterias = new ArrayList<QueryCriteria>();
						queryCriterias.add(queryCriteria);
						queryCriterias.add(queryCriteria1);
						queryUtil.setQueryCriterias(queryCriterias);
					}
				}
			}
		}
		List<RemouldProjectListDTO> projectList = remouldProjectListReadMapper.queryList(queryUtil);
		if (projectList != null && projectList.size() > 0) {
			for (RemouldProjectListDTO remouldProjectListDTO : projectList) {
				PropertyDTO propertyDTO = remouldProjectListDTO.getPropertyDTO();
				if (propertyDTO != null
						&& propertyDTO != null) {
					buildAddressDTO(propertyDTO);
				}
			}
		}
		return projectList;
	}

	//项目变更
	@Override
	public void changeRemouldProject(Integer id){
		//根据获取到的项目编号来改变项目的状态
		RemouldProject remouldProject = remouldProjectReadMapper.selectByPrimaryKey(id);
		remouldProject.setAuditStatus("R155");
		remouldProjectWriteMapper.updateByPrimaryKeySelective(remouldProject);
		//TODO发通知给城市经理
		remouldProject = remouldProjectReadMapper.selectByPrimaryKey(id);
		remouldProject.setAuditStatus("R154");
		remouldProjectWriteMapper.updateByPrimaryKeySelective(remouldProject);
		//城市经理通过以后，将记录保存到审核日志表中
		AuditLog al = new AuditLog();
		al.setRemouldProjectId(remouldProject.getId());
		Integer cityManager = remouldProject.getProjectManager();
		User user = userReadMapper.selectByPrimaryKey(cityManager);
		Integer personalInfoId = user.getPersonalInfoId();
		PersonalInfo pi = personalInfoReadMapper.selectByPrimaryKey(personalInfoId);
		String firstName  = pi.getFirstName();
		String lastName = pi.getLastName();
		String cityManagerName = firstName+lastName;
		al.setName(cityManagerName);
		al.setPost("RC002");
		al.setResult("通过");
		auditLogWriteMapper.insertSelective(al);
	}

	@Override
	public void replaceContent(Integer newProjectId, Integer oldProjectId) throws BusinessException {
		List<Procedure> oldProcedureList = procedureServiceImpl.getByProjectId(oldProjectId);
		if (oldProcedureList != null && oldProcedureList.size() > 0) {
			for (Procedure procedure : oldProcedureList) {
				this.removeProcedure(oldProjectId, procedure.getId());
			}
		}
		RemouldProject remouldProject = (RemouldProject) this.get(newProjectId);
		remouldProjectWriteMapper.deleteByPrimaryKey(remouldProject);

		remouldProject.setId(oldProjectId);
		this.update(remouldProject);

		List<Procedure> newProcedureList = procedureServiceImpl.getByProjectId(newProjectId);
		if (newProcedureList != null && newProcedureList.size() > 0) {
			for (Procedure procedure : newProcedureList) {
				remouldProjectWriteMapper.deleteRemouldProjectProcedure(newProjectId, procedure.getId());
				remouldProjectWriteMapper.insertRemouldProjectProcedure(oldProjectId, procedure.getId());
			}
		}

	}

}
